#pragma once

#include <iostream>
#include <unistd.h>
#include <memory>
#include <vector>
#include <functional>
#include <unordered_map>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class TimeTask
{
public:
    TimeTask(uint64_t id, uint32_t timeout, const TaskFunc& cb)
        :_id(id)
        ,_timeout(timeout)
        ,_task_cb(cb)
        ,_canceled(false)
    {}

    ~TimeTask()
    {
        if(_canceled == false)
            _task_cb();
        _release();
    }

    void Cancel()
    {
        _canceled = true;
    }

    void SetRelease(const ReleaseFunc& cb)
    {
        _release = cb;
    }

    uint32_t Delaytime()
    {
        return _timeout;
    }
private:
    uint64_t _id;
    uint32_t _timeout;
    bool _canceled;
    TaskFunc _task_cb;
    ReleaseFunc _release;
};

class TimeWheel
{
public:
    TimeWheel()
        :_tick(0)
        ,_capacity(60)
        ,_wheel(_capacity)
    {}

    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc& cb)
    {
        PtrTask pt(new TimeTask(id, delay, cb));
        pt->SetRelease(std::bind(&TimeWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        _timers[id] = WeakTask(pt);
        // std::cout <<"添加任务成功， 任务id:" << id << std::endl;
    }

    void TimeRefresh(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;
        PtrTask pt = it->second.lock();
        int delay = pt->Delaytime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
        // std::cout <<"刷新定时任务成功， 任务id:" << id << std::endl;
    }

    void TimeCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;
        PtrTask pt = it->second.lock();
        if(pt) pt->Cancel();
    }

    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear();
    }
private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if(it == _timers.end())
            return;
        _timers.erase(id);
    }
private:
    using WeakTask = std::weak_ptr<TimeTask>;
    using PtrTask = std::shared_ptr<TimeTask>;
    int _tick;
    int _capacity;
    std::vector<std::vector<PtrTask>> _wheel;
    std::unordered_map<uint64_t, WeakTask> _timers;
};